﻿Imports System
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.Activities.Rules
    Friend Class SimpleRunTimeTypeProvider
        Implements ITypeProvider
        ' Events
        Public Custom Event TypeLoadErrorsChanged As EventHandler
        Public Custom Event TypesChanged As EventHandler

        ' Methods
        Friend Sub New(ByVal startingAssembly As Assembly)
            Me.root = startingAssembly
        End Sub

        Public Function [GetType](ByVal name As String) As Type
            Return Me.GetType(name, False)
        End Function

        Public Function [GetType](ByVal name As String, ByVal throwOnError As Boolean) As Type
            Dim type As Type = Me.root.GetType(name, throwOnError, False)
            If (Not type Is Nothing) Then
                Return type
            End If
            type = Type.GetType(name, throwOnError, False)
            If (Not type Is Nothing) Then
                Return type
            End If
            Dim assembly As Assembly
            For Each assembly In Me.ReferencedAssemblies
                type = [assembly].GetType(name, throwOnError, False)
                If (Not type Is Nothing) Then
                    Return type
                End If
            Next
            Dim assemblies As Assembly() = AppDomain.CurrentDomain.GetAssemblies
            Dim i As Integer
            For i = 0 To assemblies.Length - 1
                type = assemblies(i).GetType(name, throwOnError, False)
                If (Not type Is Nothing) Then
                    Return type
                End If
            Next i
            Return Nothing
        End Function

        Public Function GetTypes() As Type()
            Dim list As New List([Of] Type)
            Try 
                list.AddRange(Me.root.GetTypes)
            Catch exception As ReflectionTypeLoadException
                Dim type As Type
                For Each type In exception.Types
                    If (Not type Is Nothing) Then
                        list.Add(type)
                    End If
                Next
            End Try
            Dim assembly As Assembly
            For Each assembly In Me.ReferencedAssemblies
                Try 
                    list.AddRange([assembly].GetTypes)
                    [Continue] For
                Catch exception2 As ReflectionTypeLoadException
                    Dim type2 As Type
                    For Each type2 In exception2.Types
                        If (Not type2 Is Nothing) Then
                            list.Add(type2)
                        End If
                    Next
                    [Continue] For
                End Try
            Next
            Return list.ToArray
        End Function


        ' Properties
        Public ReadOnly Property LocalAssembly As Assembly
            Get
                Return Me.root
            End Get
        End Property

        Public ReadOnly Property ReferencedAssemblies As ICollection([Of] Assembly)
            Get
                If (Me.references Is Nothing) Then
                    Dim list As New List([Of] Assembly)
                    Dim name As AssemblyName
                    For Each name In Me.root.GetReferencedAssemblies
                        list.Add(Assembly.Load(name))
                    Next
                    Me.references = list
                End If
                Return Me.references
            End Get
        End Property

        Public ReadOnly Property TypeLoadErrors As IDictionary([Of] Object, Exception)
            Get
                Me.TypesChanged.Invoke(Me, Nothing)
                Me.TypeLoadErrorsChanged.Invoke(Me, Nothing)
                Return Nothing
            End Get
        End Property


        ' Fields
        Private references As List([Of] Assembly)
        Private root As Assembly
    End Class
End Namespace

